package service

import (
	"errors"
	"fmt"
	"github.com/cn-ygf/go-admin/internal/modular/system/dao"
	"github.com/cn-ygf/go-admin/internal/modular/system/model"
	"github.com/cn-ygf/go-admin/internal/modular/system/vo"
	"github.com/cn-ygf/go-admin/pkg/utils"
)

var (
	UserService = new(userService)
)

var (
	UserNameUniqueError = errors.New("用户名已存在")
)

// userService 用户管理
type userService struct {
}

// QueryList 分页查询用户列表
func (s userService) QueryList(req *vo.QueryUserListReq) ([]*model.SysUser, int64, error) {
	var (
		u = dao.SysUser
		d = u.Where()
	)
	if req.PageSize < 1 {
		req.PageSize = 10
	}
	if req.PageNum < 1 {
		req.PageNum = 1
	}
	if req.UserName != "" {
		d = d.Where(u.UserName.Like("%" + req.UserName + "%"))
	}
	if req.NickName != "" {
		d = d.Where(u.NickName.Like("%" + req.NickName + "%"))
	}
	if req.Status != "" {
		d = d.Where(u.Status.Eq(req.Status))
	}
	if req.Phonenumber != "" {
		d = d.Where(u.Phonenumber.Eq(req.Phonenumber))
	}
	if req.Params != nil {
		if req.Params.BeginTime > 0 && req.Params.EndTime > 0 {
			d = d.Where(u.CreatedAt.Gte(req.Params.BeginTime))
			d = d.Where(u.CreatedAt.Lte(req.Params.EndTime))
		}
	}

	if req.DeptId > 0 {
		deptIds, err := DeptService.GetChild(req.DeptId)
		if err != nil {
			return nil, 0, err
		}
		deptIds = append(deptIds, req.DeptId)
		d = d.Where(u.DeptID.In(deptIds...))
	}
	return d.FindByPage((req.PageNum-1)*req.PageSize, req.PageSize)
}

// All 查询所有用户
func (s userService) All() ([]*model.SysUser, error) {
	return dao.SysUser.Find()
}

// GetByDeptID 根据部门id获取用户
func (s userService) GetByDeptID(deptId int64) ([]*model.SysUser, error) {
	var (
		u = dao.SysUser
		d = u.Where()
	)

	deptIds, err := DeptService.GetChild(deptId)
	if err != nil {
		return nil, err
	}
	deptIds = append(deptIds, deptId)
	d = d.Where(u.DeptID.In(deptIds...))
	return d.Find()
}

// GetIdsByDeptID 根据部门id获取用户
func (s userService) GetIdsByDeptID(deptId int64) ([]int64, error) {
	var (
		u = dao.SysUser
		d = u.Where()
	)

	deptIds, err := DeptService.GetChild(deptId)
	if err != nil {
		return nil, err
	}
	deptIds = append(deptIds, deptId)
	d = d.Where(u.DeptID.In(deptIds...))
	users, err := d.Find()
	if err != nil {
		return nil, err
	}
	userIds := make([]int64, len(users))
	for idx, item := range users {
		userIds[idx] = item.UserID
	}
	return userIds, nil
}

// GetIdsByDeptIDEx 只获取当前部门
func (s userService) GetIdsByDeptIDEx(deptId int64) ([]int64, error) {
	var (
		u = dao.SysUser
		d = u.Where()
	)
	d = d.Where(u.DeptID.Eq(deptId))
	users, err := d.Find()
	if err != nil {
		return nil, err
	}
	userIds := make([]int64, len(users))
	for idx, item := range users {
		userIds[idx] = item.UserID
	}
	return userIds, nil
}

// GetByID 根据userId查询用户
func (s userService) GetByID(userId int64) (*model.SysUser, error) {
	return dao.SysUser.Where(dao.SysUser.UserID.Eq(userId)).First()
}

// GetByUserName 根据用户名查询
// username 用户名
func (s userService) GetByUserName(username string) (*model.SysUser, error) {
	return dao.SysUser.Where(dao.SysUser.UserName.Eq(username)).First()
}

// GetUserRolesByID 根据用户id获取角色
// 返回角色key
func (s userService) GetUserRolesByID(userId int64) ([]string, error) {
	roleList, err := dao.SysRole.Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	roles := make([]string, 0)
	userRoleList, err := dao.SysUserRole.Where(dao.SysUserRole.UserID.Eq(userId)).Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return roles, nil
	}
	for _, item := range userRoleList {
		for _, role := range roleList {
			if item.RoleID == role.RoleID {
				roles = append(roles, role.RoleKey)
			}
		}
	}

	return roles, nil
}

// GetUserRolesNameByID 根据用户id获取角色
// 返回角色名称
func (s userService) GetUserRolesNameByID(userId int64) ([]string, error) {
	roleList, err := dao.SysRole.Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	roles := make([]string, 0)
	userRoleList, err := dao.SysUserRole.Where(dao.SysUserRole.UserID.Eq(userId)).Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return roles, nil
	}
	for _, item := range userRoleList {
		for _, role := range roleList {
			if item.RoleID == role.RoleID {
				roles = append(roles, role.RoleName)
			}
		}
	}

	return roles, nil
}

// GetUserDataScope 获取用户数据权限范围
// 返回可访问的用户id值
func (s userService) GetUserDataScope(userId int64) ([]int64, error) {
	// 获取用户
	user, err := s.GetByID(userId)
	if err != nil {
		return nil, DatabaseError
	}
	// 获取用户角色
	roles, err := s.GetUserRoleByID(userId)
	if err != nil {
		return nil, DatabaseError
	}
	for _, role := range roles {
		// 所有
		if role.DataScope == "1" {
			return nil, nil
		}
	}
	for _, role := range roles {
		// 本部门及子部门
		if role.DataScope == "4" {
			return s.GetIdsByDeptID(user.DeptID)
		}
	}
	for _, role := range roles {
		// 本部门
		if role.DataScope == "3" {
			// 获取本部门的所有用户id
			return s.GetIdsByDeptIDEx(user.DeptID)
		}
	}
	for _, role := range roles {
		// 本人
		if role.DataScope == "5" {
			return []int64{user.UserID}, nil
		}
	}
	return []int64{}, nil
}

// GetUserRoleByID 根据用户id获取角色
// 返回角色
func (s userService) GetUserRoleByID(userId int64) ([]*model.SysRole, error) {
	roleList, err := dao.SysRole.Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	roles := make([]*model.SysRole, 0)
	userRoleList, err := dao.SysUserRole.Where(dao.SysUserRole.UserID.Eq(userId)).Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return roles, nil
	}
	for _, item := range userRoleList {
		for _, role := range roleList {
			if item.RoleID == role.RoleID && role.Status == "0" {
				roles = append(roles, role)
			}
		}
	}

	return roles, nil
}

// GetUserRoleIdsByID 根据用户id获取角色
// 返回角色ids
func (s userService) GetUserRoleIdsByID(userId int64) ([]int64, error) {
	roleList, err := dao.SysRole.Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	roles := make([]int64, 0)
	userRoleList, err := dao.SysUserRole.Where(dao.SysUserRole.UserID.Eq(userId)).Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return roles, nil
	}
	for _, item := range userRoleList {
		for _, role := range roleList {
			if item.RoleID == role.RoleID && role.Status == "0" {
				roles = append(roles, role.RoleID)
			}
		}
	}

	return roles, nil
}

// GetUserFirstPostByID 获取用户第一个岗位
func (s userService) GetUserFirstPostByID(userId int64) (*model.SysPost, error) {
	up, err := dao.SysUserPost.Where(dao.SysUserPost.UserID.Eq(userId)).First()
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, nil
	}
	return PostService.GetByID(up.PostID)
}

// GetUserPostIdsByID 根据用户id获取岗位
// 返回部门ids
func (s userService) GetUserPostIdsByID(userId int64) ([]int64, error) {
	postList, err := dao.SysPost.Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	posts := make([]int64, 0)
	userPostList, err := dao.SysUserPost.Where(dao.SysUserPost.UserID.Eq(userId)).Find()
	if err != nil {
		systemLog.Errorln(err.Error())
		return posts, nil
	}
	for _, item := range userPostList {
		for _, post := range postList {
			if item.PostID == post.PostID && post.Status == "0" {
				posts = append(posts, post.PostID)
			}
		}
	}

	return posts, nil
}

// GetMenuPermission 获取用户相关菜单权限
func (s userService) GetMenuPermission(userId int64) ([]string, error) {
	permissions := make([]string, 0)
	if s.IsAdmin(userId) {
		permissions = append(permissions, "*:*:*")
	} else {
		menuList, err := dao.SysMenu.Find()
		if err != nil {
			systemLog.Errorln(err.Error())
			return permissions, nil
		}
		roleIds, err := s.GetUserRoleIdsByID(userId)
		if err != nil {
			systemLog.Errorln(err.Error())
			return permissions, nil
		}
		userMenuList, err := dao.SysRoleMenu.Where(dao.SysRoleMenu.RoleID.In(roleIds...)).Find()
		if err != nil {
			systemLog.Errorln(err.Error())
			return permissions, nil
		}
		for _, menu := range menuList {
			for _, um := range userMenuList {
				if um.MenuID == menu.MenuID {
					if menu.Status == "0" && menu.MenuType != "M" {
						permissions = append(permissions, menu.Perms)
					}
				}
			}
		}
	}

	return permissions, nil
}

// ChangeStatus 修改用户状态
func (s userService) ChangeStatus(userId int64, status string) error {
	_, err := dao.SysUser.Where(dao.SysUser.UserID.Eq(userId)).Update(dao.SysUser.Status, status)
	return err
}

// ChangePassword 修改用户密码
func (s userService) ChangePassword(userId int64, password string) error {
	password = utils.EncryptPassword(password)
	_, err := dao.SysUser.Where(dao.SysUser.UserID.Eq(userId)).Update(dao.SysUser.Password, password)
	return err
}

// Add 添加用户
func (s userService) Add(req *vo.AddUserReq) error {
	if !s.CheckUserNameUnique(req.UserName) {
		return UserNameUniqueError
	}
	u := dao.SysUser
	newUser := &model.SysUser{
		DeptID:      req.DeptId,
		UserName:    req.UserName,
		NickName:    req.NickName,
		UserType:    "00",
		Email:       req.Email,
		Phonenumber: req.Phonenumber,
		Sex:         req.Sex,
		Avatar:      "",
		Password:    utils.EncryptPassword(req.Password),
		Status:      req.Status,
		CreateBy:    req.CreateBy,
		Remark:      req.Remark,
	}
	err := u.Create(newUser)
	if err != nil {
		systemLog.Errorln(err.Error())
		return ServerError
	}
	if req.PostIds != nil {
		postLen := len(req.PostIds)
		if postLen > 0 {
			ups := make([]*model.SysUserPost, postLen)
			for index, item := range req.PostIds {
				ups[index] = &model.SysUserPost{
					UserID: newUser.UserID,
					PostID: item,
				}
			}
			err = dao.SysUserPost.CreateInBatches(ups, postLen)
			if err != nil {
				systemLog.Errorln(err.Error())
				return ServerError
			}
		}
	}
	if req.RoleIds != nil {
		roleLen := len(req.RoleIds)
		if roleLen > 0 {
			urs := make([]*model.SysUserRole, roleLen)
			for index, item := range req.RoleIds {
				urs[index] = &model.SysUserRole{
					UserID: newUser.UserID,
					RoleID: item,
				}
			}
			err = dao.SysUserRole.CreateInBatches(urs, roleLen)
			if err != nil {
				systemLog.Errorln(err.Error())
				return ServerError
			}
		}
	}
	return nil
}

func (s userService) UpdateProfile(userId int64, req *vo.EditUserProfileReq) error {
	u := dao.SysUser
	_, err := u.Where(u.UserID.Eq(userId)).Updates(map[string]any{
		u.NickName.ColumnName().String():    req.NickName,
		u.Email.ColumnName().String():       req.Email,
		u.Phonenumber.ColumnName().String(): req.Phonenumber,
		u.Sex.ColumnName().String():         req.Sex,
	})
	if err != nil {
		systemLog.Errorln(err.Error())
		return ServerError
	}
	return nil
}

// Update 修改用户
func (s userService) Update(req *vo.EditUserReq) error {
	u := dao.SysUser
	_, err := u.Where(u.UserID.Eq(req.UserId)).Updates(map[string]any{
		u.NickName.ColumnName().String():    req.NickName,
		u.Email.ColumnName().String():       req.Email,
		u.Phonenumber.ColumnName().String(): req.Phonenumber,
		u.Sex.ColumnName().String():         req.Sex,
		u.Status.ColumnName().String():      req.Status,
		u.Remark.ColumnName().String():      req.Remark,
		u.DeptID.ColumnName().String():      req.DeptId,
		u.UpdateBy.ColumnName().String():    req.UpdateBy,
	})
	if err != nil {
		systemLog.Errorln(err.Error())
		return ServerError
	}
	_, err = dao.SysUserPost.Where(dao.SysUserPost.UserID.Eq(req.UserId)).Delete()
	if err != nil {
		systemLog.Errorln(err.Error())
		return ServerError
	}
	_, err = dao.SysUserRole.Where(dao.SysUserRole.UserID.Eq(req.UserId)).Delete()
	if err != nil {
		systemLog.Errorln(err.Error())
		return ServerError
	}
	if req.PostIds != nil {
		postLen := len(req.PostIds)
		if postLen > 0 {
			ups := make([]*model.SysUserPost, postLen)
			for index, item := range req.PostIds {
				ups[index] = &model.SysUserPost{
					UserID: req.UserId,
					PostID: item,
				}
			}
			err = dao.SysUserPost.CreateInBatches(ups, postLen)
			if err != nil {
				systemLog.Errorln(err.Error())
				return ServerError
			}
		}
	}
	if req.RoleIds != nil {
		roleLen := len(req.RoleIds)
		if roleLen > 0 {
			urs := make([]*model.SysUserRole, roleLen)
			for index, item := range req.RoleIds {
				urs[index] = &model.SysUserRole{
					UserID: req.UserId,
					RoleID: item,
				}
			}
			err = dao.SysUserRole.CreateInBatches(urs, roleLen)
			if err != nil {
				systemLog.Errorln(err.Error())
				return ServerError
			}
		}
	}
	return nil
}

// AuthRole 给用户授权角色
func (s userService) AuthRole(userId int64, roleIds []int64) error {
	_, err := dao.SysUserRole.Where(dao.SysUserRole.UserID.Eq(userId)).Delete()
	if err != nil {
		systemLog.Errorln(err.Error())
		return ServerError
	}
	if roleIds != nil {
		roleLen := len(roleIds)
		if roleLen > 0 {
			urs := make([]*model.SysUserRole, roleLen)
			for index, item := range roleIds {
				urs[index] = &model.SysUserRole{
					UserID: userId,
					RoleID: item,
				}
			}
			err = dao.SysUserRole.CreateInBatches(urs, roleLen)
			if err != nil {
				systemLog.Errorln(err.Error())
				return ServerError
			}
		}
	}
	return nil
}

// Import 导入用户
func (s userService) Import(list []*vo.AddUserReq, update bool) string {
	var (
		successNum int64
		failureNum int64
		message    string
	)
	for _, item := range list {
		user, err := s.GetByUserName(item.UserName)
		if err != nil {
			err = s.Add(item)
			if err != nil {
				failureNum++
				message += fmt.Sprintf("<br/>%d、账号 %s 导入失败", failureNum, item.UserName)
				continue
			}
			successNum++
			message += fmt.Sprintf("<br/>%d、账号 %s 导入成功", successNum, item.UserName)
			continue
		}
		if update {
			err = s.Update(&vo.EditUserReq{
				UserId:      user.UserID,
				NickName:    item.NickName,
				Email:       item.Email,
				Phonenumber: item.Phonenumber,
				Sex:         item.Sex,
				Status:      item.Status,
				DeptId:      item.DeptId,
				PostIds:     nil,
				RoleIds:     nil,
				UpdateBy:    item.CreateBy,
			})
			if err != nil {
				failureNum++
				message += fmt.Sprintf("<br/>%d、账号 %s 导入失败", failureNum, item.UserName)
				continue
			}
			successNum++
			message += fmt.Sprintf("<br/>%d、账号 %s 更新成功", successNum, item.UserName)
			continue
		} else {
			failureNum++
			message += fmt.Sprintf("<br/>%d、账号 %s 已存在", failureNum, item.UserName)
		}

	}
	message = fmt.Sprintf("导入完成，成功：%d条，失败：%d条，数据如下：", successNum, failureNum) + message
	return message
}

// Delete 删除用户
func (s userService) Delete(userIds []int64) error {
	_, err := dao.SysUser.Where(dao.SysUser.UserID.In(userIds...)).Delete()
	return err
}

// IsAdmin 判断用户id是否为系统管理员自带账号
func (s userService) IsAdmin(userId int64) bool {
	if userId == 1 {
		return true
	}
	// 判断角色是否为超级管理员
	roleIds, err := s.GetUserRoleIdsByID(userId)
	if err != nil {
		systemLog.Errorln(err.Error())
		return false
	}
	return utils.IdsContains(roleIds, 1)
}

// HasPermi 判断用户是否有该权限
// userId 用户id
// permi 权限标识
func (s userService) HasPermi(userId int64, permi string) bool {
	if UserService.IsAdmin(userId) {
		return true
	}
	permis, err := s.GetMenuPermission(userId)
	if err != nil {
		return false
	}
	for _, item := range permis {
		if item == permi {
			return true
		}
	}
	return false
}

// CheckUserNameUnique 检查用户名是否已存在
func (s userService) CheckUserNameUnique(userName string) bool {
	count, err := dao.SysUser.Where(dao.SysUser.UserName.Eq(userName)).Count()
	if err != nil {
		systemLog.Errorln(err.Error())
		return true
	}
	return count < 1
}
